#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spinlock.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/usb.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/hid.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <video/display_timing.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/fb.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
#include <video/videomode.h>
#include <linux/list.h>
#include <linux/input.h>
#include <linux/timer.h>

struct jz_gpio_port {
	struct gpio_chip gc;
    struct device *dev;
};

static int g_gpio_val = 0;

static int jz_bgpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
    dev_err(NULL, "set pin %d as input\n", offset);

    return 0;
}

static int jz_bgpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
{
    dev_err(NULL, "set pin %d as output %s\n", offset, value ? "high" : "low");

    return 0;
}

static int jz_bgpio_get(struct gpio_chip *chip, unsigned offset)
{
	int val;
	val = (g_gpio_val & (1 << offset)) ? 1 : 0;
    dev_err(NULL, "get pin %d, it's val = %d\n", offset, val);
	return val;
}

static void jz_bgpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
    dev_err(NULL, "set pin %d as %d\n", offset, value);
	if (value)
		g_gpio_val |= (1 << offset);
	else
		g_gpio_val &= ~(1 << offset);
}

static int jz_gpio_ctrl_probe(struct platform_device *pdev)
{
    struct device_node *np = NULL;
    struct device *dev = &pdev->dev;
    struct jz_gpio_port *chip = NULL;
    unsigned int val = 0;
    int ret = 0;

    np = dev->of_node;
    if (!np) {
        dev_err(dev, "could not find device info\n");
        return -EINVAL;
    }

    /* 1.分配gpio_chip */
    chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
    if (!chip) {
        return -ENOMEM;
    }

    chip->dev = &pdev->dev;

    /* 设置gpio_chip函数 */
    chip->gc.label = dev_name(&pdev->dev);
    chip->gc.direction_input = jz_bgpio_direction_input;
    chip->gc.direction_output = jz_bgpio_direction_output;
    chip->gc.get = jz_bgpio_get;
    chip->gc.set = jz_bgpio_set;
    
    chip->gc.parent = &pdev->dev;
    chip->gc.owner = THIS_MODULE;

    /* 设置base,ngpio值 */
    chip->gc.base = -1;
    /* 获取gpio的个数 */
    ret = of_property_read_u32(np, "ngpios", &val);
    if (ret != 0) {
        dev_err(NULL, "get ngpios failed\n");
        return -EBUSY;
    }
    chip->gc.ngpio = val;

    /* 注册gpio_chip */
    ret = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
    if (ret) {
        dev_err(NULL, "devm_gpiochip_add_data failed\n");
        return -EBUSY;
    }

    return 0;
}

static int jz_gpio_ctrl_remove(struct platform_device *pdev)
{
    return 0;
}

static const struct of_device_id vir_pinctrl_drv[] = {
    { .compatible = "jz2440,virtual_gpio_ctrl", },
    {},
};
MODULE_DEVICE_TABLE(of, vir_pinctrl_drv);

static struct platform_driver vir_gpio_controller_driver = {
    .probe = jz_gpio_ctrl_probe,
    .remove = jz_gpio_ctrl_remove,
    .driver = {
        .name = "jz2440-vir-gpio-ctrl",
        .of_match_table = of_match_ptr(vir_pinctrl_drv),
    }
};

/*
 * init入口函数
*/
static int vir_gpio_controller_drv_init(void)
{
    int ret = platform_driver_register(&vir_gpio_controller_driver);
    if (ret < 0) {
        dev_err(NULL, "vir_gpio_controller_drv_init failed\n");
        return -EBUSY;
    }
    
    return ret;
}

/*
 * exit出口函数
 */
static void vir_gpio_controller_drv_exit(void)
{
    platform_driver_unregister(&vir_gpio_controller_driver);
    return;
}

module_init(vir_gpio_controller_drv_init);
module_exit(vir_gpio_controller_drv_exit);

MODULE_AUTHOR("huang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("platform pinctrl drv");

